/* 中断中不允许使用printf */
#include <stdio.h>
#include "usbprint.h"
#include "usbd_common.h"

typedef struct
{
    volatile uint8_t lock;
    volatile uint8_t sofcnt;
    volatile int cnt;
    volatile char *tx_ptr;
    volatile char *rx_ptr;
} USBPrint_Handler;

#define BUFF_SIZE 1024

#ifdef USB_PRINT

static char buff[BUFF_SIZE];
static USBPrint_Handler hUsbPrint = {
    .tx_ptr = (char*)buff,
    .rx_ptr = (char*)buff,
    .cnt = 0
};

static void USBPrint_Put(char c)
{
    if (hUsbPrint.cnt < BUFF_SIZE)
    {
        hUsbPrint.lock = 1;
        *hUsbPrint.rx_ptr = c;
        hUsbPrint.rx_ptr++;
        if (hUsbPrint.rx_ptr == &buff[0] + BUFF_SIZE)
        {
            hUsbPrint.rx_ptr = &buff[0];
        }
        hUsbPrint.cnt++;
        hUsbPrint.lock = 0;
    }
}

uint8_t USBPrint_SOF_IRQHandler(USBD_HandleTypeDef *pdev)
{
    uint8_t ret = USBD_OK;
    USBD_CDC_HandleTypeDef *hcdc = USBD_GETHANDLE_CDC(pdev);
    if (hcdc->TxState == 0U && hUsbPrint.lock == 0U)
    {
        /* 每5个SOF尝试发送缓冲区 */
        if (hUsbPrint.sofcnt < 5)
        {
            hUsbPrint.sofcnt++;
            return ret;
        }
        
        hUsbPrint.sofcnt = 0;

        /* 最大可发送数量 */
        uint16_t cnt = MIN(&buff[0] + BUFF_SIZE - hUsbPrint.tx_ptr, hUsbPrint.cnt);
        if (cnt)
        {
            if (pdev->pClassData != NULL)
            {
                USBD_CDC_SetTxBuffer(pdev, (uint8_t*)hUsbPrint.tx_ptr, cnt);
                USBD_CDC_TransmitPacket(pdev);
                hUsbPrint.cnt -= cnt;
                hUsbPrint.tx_ptr += cnt;
                /* 发送指针复位 */
                if (hUsbPrint.tx_ptr == &buff[0] + BUFF_SIZE)
                {
                    hUsbPrint.tx_ptr = &buff[0];
                }
            }
        }
    }
    return ret;
}


int fputc(int ch, FILE *stream)
{
    USBPrint_Put(ch);
    return ch;
}

#endif
